home *** CD-ROM | disk | FTP | other *** search
- /*
- * Simple mail user interface for KA9Q IP/TCP package.
- * A.D. Barksdale Garbee II, aka Bdale, N3EUA
- * Copyright 1986 Bdale Garbee, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- * Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- *
- * revision history:
- *
- * v3.3 870467 D. Trulli nn2z
- * v3.2 870314 D. Trulli nn2z
- * v3.1 870117 D. Trulli nn2z
- * Add multiple arguments mail commands.
- * Send to multiple users.
- * Add status commands;
- * v3.0 871225 D. Trulli nn2z
- * Heavily restructured program to use a index array of message.
- * More compatible with UNIX type mail commands.
- * v2.7 871214 D. Trulli nn2z
- * Cleaned up header and message parsing to prevent lock up.
- * Revised command structure.
- * v2.6 870826 Bdale
- * integrate PA0GRI's interface/gateway to the WA7MBL PBBS
- * v2.5 870713 Bdale
- * integrate additional patches from PA0GRI, minor cleanup
- * v2.4 870614 - P. Karn
- * "smart gateway" function moved to smtp client code in net.exe.
- * User interface for sending mail reworked to resemble Berkeley Mail
- * v2.3 870524
- * Extensive addition/revision by Gerard PA0GRI. Now supports a healthy
- * set of real commands.
- * v2.1,2.2
- * exact change history lost.
- * v2.0 c.870115
- * First version with command parser, only send and quit work.
- * v1.0
- * First attempt. Send messages only.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include "bm.h"
-
- extern char version[];
- static char copyright1[] =
- "Copyright 1987 Bdale Garbee, permission granted for non-commercial use.";
- static char copyright2[] =
- "Copyright 1988 Dave Trulli NN2Z, permission granted for non-commercial use.";
-
- /* comands valid in bm.rc */
-
- struct token rccmds[] = {
- "smtp", SMTP,
- "host", HOST,
- "user", USER,
- "edit", EDIT,
- "fullname", NAME,
- "reply", REPLY,
- "maxlet", MAXLET,
- "mbox", MBOX,
- "record", RECORD,
- "screen", SCREEN,
- "folder", FOLDER,
- "mqueue", MQUEUE,
- NULLCHAR, 0
- };
-
- FILE *mfile = NULLFILE;
- char *hostname = NULLCHAR; /* name of this host from rc file */
- char *username = NULLCHAR; /* name of this user from rc file */
- char *fullname = NULLCHAR; /* fullname of this user from rc file */
- char *replyto = NULLCHAR; /* address for reply-to header */
- char *maildir = NULLCHAR; /* defined mail directory */
- char *mqueue = NULLCHAR; /* defined mqueue outbound directory */
- char *savebox = NULLCHAR; /* name of the mbox text file */
- char *record = NULLCHAR; /* record outbound mail in this file */
- char *folder = NULLCHAR; /* directory for saveing read mail */
- char *editor = NULLCHAR; /* user's favorite text editor */
- char notename[9]; /* name of current notesfile */
- char notefile[SLINELEN]; /* full pathname of mail text file */
- char *mfilename = notefile; /* pointer to current mbox or mail file -f */
- int current; /* the current message number */
- int nmsgs; /* the number of messages in the notesfile */
- int newmsgs; /* Number of new unread message */
- int change; /* indicates that the mail file has been
- * changed in this session */
- int fflag = 0; /* true if current notesfile is not an mbox */
- int qflag = 0; /* true if bm is used just to queue files */
- unsigned maxlet = NLET+1; /* max number of messages in mailbox */
- int tty = 0; /* tells if stdin is a tty */
- struct let *mbox; /* pointer to the array of messages */
-
-
- char usage[] = "Usage: bm [-u user] [-f file] \n or bm [-s subject] [-q] addr .. addr\n";
- char badmsg[] = "Invalid Message number %d\n";
- char nomail[] = "No messages\n";
- char noaccess[] = "Unable to access %s\n";
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- extern int optind;
- extern char *optarg;
- char *subjectline = NULLCHAR;
- long tmp;
- int c;
- int ret;
-
- #if defined(__TURBOC__) || defined(MICROSOFT)
- (void) fclose(stdaux);
- (void) fclose(stdprn);
- #endif
-
- loadconfig();
-
- if (qflag == 0 && isatty(fileno(stdin))) {
- /* announce ourselves */
- screen_clear();
- printf(" %s\n%s\n%s\n\n",version,copyright1,copyright2);
- tty = 1;
- }
-
- current = 1;
- nmsgs = 0;
-
- /* check for important directories */
- if(access(maildir,0)){
- printf(noaccess,maildir);
- exit(1);
- }
- if(access(mqueue,0)){
- printf(noaccess,mqueue);
- exit(1);
- }
- strncpy(notename,username,8);
- notename[8] = '\0';
-
- while ((c = getopt(argc,argv,"u:f:s:q")) != -1) {
- switch(c) {
- case 'f':
- fflag++;
- mfilename = optarg;
- break;
- case 'q':
- qflag++;
- break;
- case 's':
- subjectline = optarg;
- break;
- case 'u':
- strncpy(notename,optarg,8);
- notename[8] = '\0';
- break;
- case '?':
- printf(usage);
- exit(1);
- }
- }
-
- /* set any signal handlers to catch break */
- setsignals();
-
- if(optind < argc){
- dosmtpsend(NULLFILE,&argv[optind],argc-optind,subjectline);
- (void) exit(0);
- }
-
- tmp = (long)maxlet * (long)sizeof(struct let);
- #ifdef MSDOS
- /*
- * Since we are in the dos small model make sure that we
- * don't overflow a unsigned short on the number bytes
- * need for mallloc. If not checked malloc will
- * succeed and we will be trashing ourself in no time.
- */
- if ((tmp & 0xffff0000) ||
- (mbox=(struct let *)malloc((unsigned short)tmp)) == (struct let *)NULL){
- #else
- if ((mbox=(struct let *)malloc((unsigned)tmp)) == (struct let *)NULL){
- #endif
- fprintf(stderr,
- "Can't allocate memory table for %d messages\n",
- maxlet);
- (void) exit(1);
- }
-
- sprintf(notefile,"%s/%s.txt",maildir,notename);
- if (!fflag && lockit())
- exit(1);
- ret = initnotes();
- if (!fflag)
- rmlock(maildir,notename);
- if (ret != 0)
- exit(1);
- listnotes();
-
- getcommand();
- return 0;
- }
-
- loadconfig()
- {
- FILE *rcfp; /* handle for the configuration file */
- char rcline[LINELEN]; /* buffer for config file reading */
- register char *s,*p;
- int line = 0;
- char runcom[LINELEN];
- char *getenv();
-
- #ifdef UNIX
- /* Try $HOME/RUNCOM */
- if ((p = getenv("HOME")) != NULLCHAR)
- sprintf(runcom, "%s/%s", p, RUNCOM);
- #else
- /* check for BMRC in the ENV */
- if ((p = getenv("BMRC")) != NULLCHAR)
- strcpy(runcom,p);
- #endif
- else
- strcpy(runcom,RUNCOM);
-
- if ((rcfp = fopen(runcom,"r")) == NULLFILE) { /* open config file */
- printf("Cannot open '%s', check your installation\n",runcom);
- (void) exit(1);
- }
- while (!feof(rcfp)) {
- if (fgets(rcline,LINELEN,rcfp) == NULLCHAR)
- break;
- line++;
- rip(rcline);
- if (*rcline == '\0' || *rcline == ';'|| *rcline == '#')
- continue;
- /* find the argument to the command */
-
- s = rcline;
- /* skip the white space */
- while(*s == ' ' || *s == '\t')
- s++;
- p = s;
- /* skip the command */
- while(*p && *p != ' ' && *p != '\t')
- p++;
- /* skip the white space */
- while(*p == ' ' || *p == '\t')
- p++;
- if (*s == '\0')
- continue;
-
- switch (rc_line_type(s)) {
- case HOST:
- hostname = savestr(p);
- break;
- case USER:
- username = savestr(p);
- break;
- case REPLY:
- replyto = savestr(p);
- break;
- case EDIT:
- editor = savestr(p);
- break;
- case SMTP:
- maildir = savestr(p);
- break;
- case NAME:
- fullname = savestr(p);
- break;
- case MAXLET:
- maxlet = atoi(p)+1;
- break;
- case MBOX:
- savebox = savestr(p);
- break;
- case RECORD:
- record = savestr(p);
- break;
- case SCREEN:
- #if defined(__TURBOC__)
- setvideo(p);
- #endif
- break;
- case FOLDER:
- folder = savestr(p);
- break;
- case MQUEUE:
- mqueue = savestr(p);
- break;
- default:
- fprintf(stderr,
- "%s: line %d Invalid command: '%s'\n",
- runcom,line,rcline);
- exit(1);
- }
- }
- (void) fclose(rcfp);
- if(maildir == NULLCHAR)
- maildir = mailspool;
- if(mqueue == NULLCHAR)
- mqueue = mailqdir;
- if(savebox == NULLCHAR)
- savebox = "mbox";
- if(hostname == NULLCHAR) {
- fprintf(stderr,"%s: hostname not set\n",runcom);
- exit(1);
- }
- if(username == NULLCHAR) {
- fprintf(stderr,"%s: username not set\n",runcom);
- exit(1);
- }
- }
-
- /* return the line_type from a line of the configuration file */
- rc_line_type(s)
- register char *s;
- {
- register struct token *tp;
- for (tp = rccmds; tp->str != NULLCHAR; tp++) {
- if (strncmp(tp->str,s,strlen(tp->str)) == 0)
- return tp->type;
- }
- return (NONE);
- }
-
- /* replace terminating end of line marker(s) with null */
- rip(s)
- register char *s;
- {
- for (; *s; s++)
- if (*s == '\r' || *s == '\n') {
- *s = '\0';
- break;
- }
- }
-
- /* copy a string return a pointer to it */
- char *
- savestr(s)
- char *s;
- {
- register char *p;
- p = malloc(strlen(s)+1);
- if (p == NULLCHAR)
- printf("No more memory\n");
- else
- strcpy(p,s);
- return p;
- }
-
- dohelp()
- {
- screen_clear();
- printf("\n\n");
- printf(" d [msglist] delete a message\n");
- printf(" m userlist mail a message\n");
- printf(" s [msglist] [file] save message in file (default mbox)\n");
- printf(" w [msglist] file save message in file no header\n");
- printf(" f [msg] forward message\n");
- printf(" b [msg] bounce message (remail)\n");
- printf(" r [msg] reply to a message\n");
- printf(" u [msglst] undelete a message\n");
- printf(" p [msglst] print message on printer (DOS only)\n");
- printf(" . display current message\n");
- printf(" h display message headers in notefile\n");
- printf(" l list unsent messages\n");
- printf(" k kill unsent messages\n");
- printf(" n [file] display or change notesfile\n");
- printf(" # where # is the number of message to read\n");
- printf(" x quit without changing mail file\n");
- printf(" q quit\n");
- printf(" ! cmd run dos command\n");
- printf(" $ sync the notefile\n");
- printf(" ? print this help screen\n");
- }
-
-
- /* save a message list in a file in mailbox format */
- savemsg(argc,argv)
- int argc;
- register char *argv[];
- {
- register char *savefile;
- int msgnum;
- int i;
- FILE *tfile;
- char buf[LINELEN];
-
- if (mfile == NULLFILE){
- printf(nomail);
- return;
- }
- if (argc == 0 || isdigit(*argv[argc - 1])) {
- savefile = savebox;
- } else {
- savefile = argv[argc - 1];
- --argc;
- /* if it is just a file name and not a path name then check
- ** for a folder path defined and use that path to
- ** save the file.
- */
- if (strpbrk(savefile,"/\\") == NULLCHAR && folder != NULLCHAR) {
- sprintf(buf,"%s/%s",folder,savefile);
- savefile = buf;
- }
- }
- if ((tfile = fopen(savefile,"a")) == NULLFILE) {
- perror(savefile);
- return;
- }
- if (argc == 0)
- msgtofile(current, tfile, 0);
- else {
- for (i = 0; i < argc; i++) {
- msgnum = atoi(argv[i]);
- if (msgnum >= 1 && msgnum <= nmsgs)
- msgtofile(msgnum, tfile, 0);
- else
- printf(badmsg,msgnum);
- }
- }
- (void) fclose(tfile);
- printf("%s appended\n",savefile);
- }
-
- #ifdef MSDOS
- /* send messages to the print device */
- printmsg(argc,argv)
- int argc;
- char *argv[];
- {
- FILE *prn;
- int msgnum;
- int i;
-
- if (mfile == NULLFILE){
- printf(nomail);
- return;
- }
- if ((prn = fopen("PRN","a")) == NULL) {
- perror("PRN");
- return;
- }
- if (argc == 0)
- msgtofile(current, prn, 0);
- else {
- for (i = 0; i < argc; i++) {
- msgnum = atoi(argv[i]);
- if (msgnum >= 1 && msgnum <= nmsgs)
- msgtofile(msgnum, prn, 0);
- else
- printf(badmsg,msgnum);
- }
- }
- fclose(prn);
- }
- #endif
-
- writemsg(argc,argv)
- int argc;
- char *argv[];
- {
- char *writefile;
- int msgnum;
- int i;
- FILE *tfile;
-
- if (mfile == NULLFILE){
- printf(nomail);
- return;
- }
- if (argc == 0 || isdigit(*argv[argc - 1])) {
- printf("no file specified\n");
- return;
- } else {
- writefile = argv[argc - 1];
- --argc;
- }
- if ((tfile = fopen(writefile,"a")) == NULLFILE) {
- perror(writefile);
- return;
- }
- if (argc == 0)
- msgtofile(current, tfile, 1);
- else {
- for (i = 0; i < argc; i++) {
- msgnum = atoi(argv[i]);
- if (msgnum >= 1 && msgnum <= nmsgs)
- msgtofile(msgnum, tfile, 1);
- else
- printf(badmsg,msgnum);
- }
- }
- (void) fclose(tfile);
- printf("%s appended\n",writefile);
- }
-
- bmexit(x)
- int x;
- {
- if(!fflag && lockit())
- exit(1);
- (void) closenotes();
- if (!fflag)
- rmlock(maildir,notename);
- exit(x);
- }
-
- /* this is the main command processing loop */
- getcommand()
- {
- FILE *tfile, *tmpfile();
- char command[LINELEN]; /* command line */
- char *args[MAXARGS];
- int nargs;
- char *cp;
- register int msgnum;
- register int i;
- int ret;
-
- printf("\nType ? for help.\n");
-
- /* command parsing loop */
- while(1) {
- printf("\"%s\"> ",notename);
- gets(command);
-
- if (feof(stdin)) /* someone hit ^Z! */
- strcpy(command,"q"); /* treat it like 'q' */
-
- if(*command == '!') {
- if (system(&command[1]))
- perror("system");
- continue;
- }
- if (*command) {
- cp = command;
- while (*cp && *cp != ' ')
- cp++;
- nargs = parse(cp,args,MAXARGS);
- }
-
- switch (*command) {
- case 'm': /* send msg */
- if (nargs == 0) {
- printf("To: ");
- gets(command);
- nargs = parse(command,args,MAXARGS);
- }
- dosmtpsend(NULLFILE,args,nargs,NULLCHAR);
- break;
-
- case 's': /* save current msg to file */
- savemsg(nargs,args);
- break;
-
- case 'w': /* write current msg to file */
- writemsg(nargs,args);
- break;
-
- case 'x': /* abort */
- (void) fclose(mfile);
- (void) exit(0);
- /* NOTREACHED */
- break;
-
- case 'p': /* print message */
- #ifdef MSDOS
- printmsg(nargs,args);
- #else
- printf("Command not available in this version\n");
- #endif
- break;
-
- case 'r': /* reply */
- if (nargs == 0)
- msgnum = current;
- else
- msgnum = atoi(args[0]);
- if (msgnum >= 1 && msgnum <= nmsgs)
- reply(msgnum);
- else
- printf(badmsg,msgnum);
- break;
-
- case 'f':
- if(nargs == 0)
- msgnum = current;
- else
- msgnum = atoi(args[0]);
- if (msgnum < 1 || msgnum > nmsgs) {
- printf(badmsg,msgnum);
- break;
- }
- if((tfile = tmpfile()) == NULLFILE)
- printf("\nCannot open temp file\n");
- else {
- msgtofile(msgnum,tfile,0);
- fseek(tfile,0L,0);
- printf("To: ");
- gets(command);
- nargs = parse(command,args,MAXARGS);
- dosmtpsend(tfile,args,nargs,NULLCHAR);
- (void) fclose(tfile);
- }
- break;
-
- case 'b': /* bounce a message */
- if(nargs == 0)
- msgnum = current;
- else
- msgnum = atoi(args[0]);
- if (msgnum < 1 || msgnum > nmsgs) {
- printf(badmsg,msgnum);
- break;
- }
- if((tfile = tmpfile()) == NULLFILE)
- printf("\nCannot open temp file\n");
- else {
- msgtofile(msgnum,tfile,0);
- fseek(tfile,0L,0);
- printf("To: ");
- gets(command);
- nargs = parse(command,args,MAXARGS);
- bouncemsg(tfile,args,nargs);
- (void) fclose(tfile);
- }
- break;
-
- case 'u':
- if (nargs == 0)
- mbox[current].status &= ~DELETE;
- else
- for (i = 0; i < nargs; i++) {
- msgnum = atoi(args[i]);
- if( msgnum >= 1 && msgnum <= nmsgs)
- mbox[msgnum].status &= ~DELETE;
- else
- printf(badmsg,msgnum);
- }
- break;
-
- case 'l': /* display unsent messages */
- listqueue();
- break;
- case 'k':
- if (nargs == 0)
- printf("No job id specified\n");
- else
- for (i = 0; i < nargs; i++)
- killjob(args[i]);
- break;
-
- case 'n': /* display or change notefiles */
- mboxnames(nargs,args);
- break;
- case 'q': /* quit */
- if (isnewmail()) {
- printf("New mail has arrived\n");
- reinit();
- } else
- bmexit(0);
- /* NOTREACHED */
- break;
- case '$':
- reinit();
- break;
-
- case 'd': /* delete a message */
- if (nargs == 0)
- delmsg(current);
- else
- for ( i = 0; i < nargs; i++) {
- msgnum = atoi(args[i]);
- if( msgnum >= 1 && msgnum <= nmsgs)
- delmsg(msgnum);
- else
- printf(badmsg,msgnum);
- }
- break;
-
- case 'h': /* list message headers in notesfile */
-
- listnotes();
- break;
-
- case '\0': /* a blank line prints next message */
- printnext();
- break;
-
- case '?': /* help */
- dohelp();
- break;
-
- case '.':
- displaymsg(current);
- break;
- default:
- if (!isdigit(*command))
- printf("Invalid command - ? for help\n");
- else {
- msgnum = atoi(command);
- if (msgnum < 0 || msgnum > nmsgs)
- printf(badmsg,msgnum);
- else {
- current = msgnum;
- displaymsg(current);
- }
- }
- break;
- }
- }
- }
-
- /* list or change mbox */
- mboxnames(argc,argv)
- int argc;
- char *argv[];
- {
- register char *cp;
- int ret;
- char line[80];
- char buf[LINELEN];
-
- if(argc != 0) {
- if(!fflag && lockit())
- return;
- ret = closenotes();
- if (!fflag)
- rmlock(maildir,notename);
- if (ret != 0)
- exit(1);
- if (strpbrk(argv[0],"/\\") != NULLCHAR) {
- fflag = 1;
- mfilename = argv[0];
- } else {
- fflag = 0;
- mfilename = notefile;
- strncpy(notename,argv[0],8);
- notename[8] = '\0';
- sprintf(notefile,"%s/%s.txt",maildir,notename);
- }
- if (!fflag && lockit()) {
- mfile = NULLFILE;
- printf("Mail file is busy\n");
- return;
- }
- ret = initnotes();
- if (!fflag)
- rmlock(maildir,notename);
- if (ret != 0)
- exit(1);
- listnotes();
-
- } else { /* he wants to see what notefiles there are */
- sprintf(buf,"%s/*.txt",maildir,notename);
- filedir(buf,0,line);
- while(line[0] != '\0') {
- cp = strchr(line,'.');
- *cp = '\0';
- printf("notesfile -> %s\n",line);
- filedir(buf,1,line);
- }
- }
- }
-
- reinit()
- {
- int ret;
- if (!fflag && lockit())
- return;
- ret = closenotes();
- if (!fflag)
- rmlock(maildir,notename);
- if (ret != 0)
- exit(1);
- if (!fflag && lockit()) {
- mfile = NULLFILE;
- printf("Mail file is busy\n");
- return;
- }
- ret = initnotes();
- if (!fflag)
- rmlock(maildir,notename);
- if (ret != 0)
- exit(1);
- listnotes();
- }
-